package com.motu.vertx.module.utility.toolset;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URLEncoder;

/**
 * 手机工具类
 * 包含发送短信验证码和校验手机格式的方法
 */
public class PhoneTools {

	public static final Logger logger = LoggerFactory.getLogger("PhoneTools");

	public static final String key = "vkbdzxbn";// 账号（当前吞吐量：30条/秒）
	public static final String secret = "qgeT6RBh";// 密码
	public static final String PAASOO_SEND_SMS_URL = "https://api.paasoo.com/json";// 短信发送URL
	public static final String PAASOO_VALID_NUMBER_URL = "https://api.paasoo.com/lookup";// 号码状态查询URL
	public static final int HTTP_REQUEST_TIMEOUT = 30000;// http请求超时时间(毫秒)
	public static final String PHONE_CODE_WORD = "[More2game]Your Verification Code:%s";// 手机验证码内容（默认文字）
	public static final String PHONE_CODE_WORD_COUNTRY = "{\"86\":\"【魔兔科技】您的验证码为：%s\"}";// 手机验证码内容（多语言）
	public static final String FROM_NAME = "More2game";// 发件人名称
	public static final String AREA_CODE_CHINA = "86";// 中国区号

	/**
	 * 发送短信验证码
	 *
	 * @param webClient web连接
	 * @param areaCode  区号（例如中国86）
	 * @param phone     手机号码（不含区号）
	 * @return 成功返回验证码，失败返回空字符串
	 */
	public static void sendPhoneCode(WebClient webClient, String areaCode, String phone, Handler<AsyncResult<String>> onComplete) {
		String code = getRandomCode();// 生成验证码
		String content = getContent(areaCode, code);
		String text;
		String phoneNumber = areaCode + phone;// 最终发送的号码是要加上区号
		try {
			text = URLEncoder.encode(content, "UTF-8");
		} catch (Exception e) {
			logger.error("sendPhoneCode error phoneNumber = " + phoneNumber + " Exception = " + Tool.getException(e));
			onComplete.handle(Future.succeededFuture(""));
			return;
		}
		String sendUrl = PAASOO_SEND_SMS_URL + "?key=" + key + "&secret=" + secret + "&from=" + FROM_NAME + "&to=" + phoneNumber + "&text=" + text;
		logger.info("sendPhoneCode url = " + sendUrl);
		webClient.getAbs(sendUrl).timeout(HTTP_REQUEST_TIMEOUT).send(res -> {
			if (res.succeeded()) {
				HttpResponse<Buffer> response = res.result();
				JsonObject resObj = response.bodyAsJsonObject();
				String status = resObj.getString("status");
				/**
				 * status 响应状态
				 * 0 - success：成功
				 * 2 - Missing parameters：缺少必要参数
				 * 3 - Invalid parameters：参数格式错误
				 * 4 - Invalid credentials：Key或Secret错误
				 * 5 - Unauthorized IP：IP限制
				 * 6 - Invalid phone number：号码格式错误
				 * 7 - Invalid sender id：from参数格式错误
				 * 8 - Message bombing detected: 3秒内重复请求
				 * 9 - Quota exceeded：欠费或信用额度不足
				 * 10 - Throttling error：超过限速
				 * 11 - System error：系统错误
				 * 19 -Invalid peid / Invalid templateid
				 */
				if (!status.equals("0")) {
					logger.error("sendPhoneCode error phoneNumber = " + phoneNumber + " response = " + resObj.toString());
					onComplete.handle(Future.succeededFuture(""));// 发送失败
				} else {
					onComplete.handle(Future.succeededFuture(code));
				}
			} else {
				logger.error("sendPhoneCode error phoneNumber = " + phoneNumber + " exception = " + Tool.getException(res.cause()));
				onComplete.handle(Future.succeededFuture(""));// 发送失败
			}
		});
	}

	/**
	 * 验证手机格式
	 *
	 * @param webClient web连接
	 * @param areaCode  区号（例如中国86）
	 * @param phone     手机号码（不含区号）
	 * @return 验证结果（true表示成功，false表示失败）
	 */
	public static void checkPhoneNumber(WebClient webClient, String areaCode, String phone, Handler<AsyncResult<Boolean>> onComplete) {
		if (areaCode.equals(AREA_CODE_CHINA)) {
			// 国内手机号码验证
			if (Tool.checkPhoneNumber(phone)) {
				onComplete.handle(Future.succeededFuture(true));
			} else {
				onComplete.handle(Future.succeededFuture(false));// 手机号码不正确
			}
		} else {
			// 海外手机号码验证
			String phoneNumber = areaCode + phone;// 最终发送的号码是要加上区号
			String sendUrl = PAASOO_VALID_NUMBER_URL + "?key=" + key + "&secret=" + secret + "&number=" + phoneNumber;
			logger.info("checkPhoneNumber url = " + sendUrl);
			webClient.getAbs(sendUrl).timeout(HTTP_REQUEST_TIMEOUT).send(res -> {
				if (res.succeeded()) {
					HttpResponse<Buffer> response = res.result();
					JsonObject resObj = response.bodyAsJsonObject();
					String errorCode = resObj.getString("errorCode");
					/**
					 * errorCode 错误编码
					 * 00 - Successful 调用成功
					 * 01 - Insufficient balance欠费
					 * 02 - Wrong credentials用户名或密码错误
					 * 03 - Missing parameters 缺少参数或者参数错误
					 * 07 - IP limit白名单限制
					 * 08 - No allow hlr 没有开通hlr查询
					 * 99 - Other error 系统错误
					 */
					int format = resObj.getInteger("format");// 0 - 无效号码  1 - 格式正确
					if (errorCode.equals("00") && format == 1) {
						onComplete.handle(Future.succeededFuture(true));
					} else {
						logger.error("checkPhoneNumber error phoneNumber = " + phoneNumber + " response = " + resObj.toString());
						onComplete.handle(Future.succeededFuture(false));// 手机号码不正确
					}
				} else {
					logger.error("checkPhoneNumber error phoneNumber = " + phoneNumber + " exception = " + Tool.getException(res.cause()));
					onComplete.handle(Future.succeededFuture(false));// 发送失败
				}
			});
		}
	}

	/**
	 * 获取验证码文字内容
	 *
	 * @param areaCode 区号
	 * @param code     验证码
	 */
	private static String getContent(String areaCode, String code) {
		String content;
		if (Tool.isEmpty(PHONE_CODE_WORD_COUNTRY)) {
			content = PHONE_CODE_WORD;
		} else {
			try {
				JsonObject jsonObject = new JsonObject(PHONE_CODE_WORD_COUNTRY);
				if (Tool.isEmpty(areaCode)) {
					areaCode = AREA_CODE_CHINA;
				}
				if (jsonObject.containsKey(areaCode)) {
					content = jsonObject.getString(areaCode);
				} else {
					content = PHONE_CODE_WORD;
				}
			} catch (Exception e) {
				logger.error("PhoneTools getContent error Exception:" + Tool.getException(e));
				content = PHONE_CODE_WORD;
			}
		}
		return String.format(content, code);
	}

	/**
	 * 获取随机验证码
	 */
	public static String getRandomCode() {
		String code = "";
		for (int i = 0; i < 4; i++) {
			int a = Tool.getRandom(1, 9);
			code += Tool.intToString(a);
		}
		return code;
	}

}
